package com.csx.micrometer.invoke.core.outbound.feign;

import com.csx.micrometer.common.util.MetricsUtil;
import com.csx.micrometer.invoke.constant.InvokeMetricsConstant;
import com.csx.micrometer.invoke.context.feign.MicrometerFeignRequest;
import com.csx.micrometer.invoke.context.feign.MicrometerFeignResponse;
import com.csx.micrometer.invoke.custom.TagsCustom;
import com.csx.micrometer.invoke.util.HttpStatusUtil;
import feign.Client;
import feign.Request;
import feign.Response;
import io.micrometer.core.instrument.Tags;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ObjectUtils;

import java.io.IOException;
import java.util.Collections;
import java.util.List;

/**
 * @author cuisongxu
 * @date 2022/12/1 15:29
 */
public class MicrometerFeignClient implements Client {

    private final Logger logger = LoggerFactory.getLogger(MicrometerFeignClient.class);

    /**
     * 代理的原始Client
     */
    private final Client delegate;

    private final List<TagsCustom> tagsCustoms;

    public MicrometerFeignClient(Client delegate, List<TagsCustom> tagsCustoms) {
        this.delegate = delegate;
        this.tagsCustoms = tagsCustoms;
    }

    @Override
    public Response execute(Request request, Request.Options options) throws IOException {
        Response response = null;
        // 自定义tags
        Tags tags = Tags.of(Collections.emptyList());
        for (TagsCustom tagsCustom : tagsCustoms) {
            tags = tagsCustom.customTags(new MicrometerFeignRequest(request), new MicrometerFeignResponse(null), tags);
        }
        logger.info("all tags custom result: " + tags.toString());
        try {
            long start = System.currentTimeMillis();
            response = this.delegate.execute(request, options);
            long end = System.currentTimeMillis();

            long responseMillis = end - start;
            if(HttpStatusUtil.isSuccess(response.status())) {
                // TODO 需要讨论调用耗时是只统计成功的还是 成功失败都统计
                // TODO 有些请求 http状态码虽然是200,但是用户自定义的返回状态码是异常的，需要在此处给用户扩展出来接口，用于用户自定义哪些是异常响应，哪些是正常响应
                MetricsUtil.record(InvokeMetricsConstant.INVOKE_RESPONSE_MILLIS, responseMillis, tags);
                MetricsUtil.counter(InvokeMetricsConstant.INVOKE_SUCCESS_TOTAL, tags).increment();
            }else {
                MetricsUtil.counter(InvokeMetricsConstant.INVOKE_FAIL_TOTAL, tags).increment();
            }
        }catch (Exception e) {
            // 统计异常状态指标
            MetricsUtil.counter(InvokeMetricsConstant.INVOKE_FAIL_TOTAL, tags).increment();
        }finally {
            MetricsUtil.counter(InvokeMetricsConstant.INVOKE_TOTAL, tags).increment();
        }
        return response;
    }


}
